import { subscribeWithSelector } from 'zustand/middleware'
import create from 'zustand'
import { isCascadeTree } from '@/pages/manager/blocks/main/table/all/utils'
import { isMatch } from '@/pages/manager/utils/utils'
import { differenceBy } from 'lodash-es'
import { IMcc } from '@/api/manager/type'
import { Mt } from '@/api/manager/mt'
import { MccModel } from '@/pages/manager/blocks/main/table/all/translator'
import { Meeting } from '@/api/manager/meeting'
import { useTableAllStore } from '@/pages/manager/blocks/main/table/all/store'
import { useTableOftenStore } from '@/pages/manager/blocks/main/table/often/store'
import { useTableInteractiveStore } from '@/pages/manager/blocks/main/table/interactive/store'
import { listToggle } from '@/utils/listSlice'

export interface ItemData {
	mcc: IMcc
	nestingLevel: number
	mtKey: string
}
export interface SelectedModel {
	mcc: Mt
	status: {
		checked: boolean
	}
	mtKey: string
}
interface IL {
	mcc: Mt
	mtKey: string
}
type Chosen = {
	_prevClickSelectItem: { start: string; prevChosen: string[] } | null
	chosenMap: { [mtKey: string]: boolean }
}
type StateStore = {
	list: ItemData[]
	tab: 'all' | 'often' | 'interactive'
	all: {
		openMap: { [mtKey: string]: boolean }
	} & Chosen
	often: Chosen
	interactive: Chosen
	selectedList: SelectedModel[]
	_start: string | null
	_changes: string[]
}
type IStore = StateStore & {
	update: (d: Partial<StateStore>) => void
	reset: () => void
	itemHandle: (mtKey: string, type: 'click' | 'ctrl' | 'shift') => void
	getListFromTableAll: (tree: MccModel<Meeting>, keywords: string) => void
	getListFromTable: <T extends IL>(list: T[], keywords: string) => void
	clickSelectItem: (data: IMcc, { ctrlKey, shiftKey }: { ctrlKey: boolean; shiftKey: boolean }) => void
	itemAddToRight: (data: Mt) => void
	clearChosen: () => void
	addAllToRight: () => void
	addAllSelectedToRight: () => void
	removeSelectedItem: (mtKey: string) => void
	removeSelectedCheckedItem: () => void
	removeAllSelectedItem: () => void
	mtChange2SelectedItem: () => void
}
const initialState: StateStore = {
	list: [],
	tab: 'all',
	all: { _prevClickSelectItem: null, chosenMap: {}, openMap: {} },
	often: { _prevClickSelectItem: null, chosenMap: {} },
	interactive: { _prevClickSelectItem: null, chosenMap: {} },
	selectedList: [],
	_start: null,
	_changes: [],
}

export const useSinglePollStore = create<IStore>()(
	subscribeWithSelector((set, get, api) => ({
		...initialState,
		update: (d) => set({ ...d }),
		reset: () => set(initialState),
		getListFromTableAll: (tree, keywords) => {
			const isCascade = isCascadeTree(tree)
			let result = []
			if (isCascade) {
				let stack: MccModel<IMcc>[] = [tree]
				let newOpenMap: { [mtKey: string]: boolean } = {}
				const openMap = get().all.openMap
				while (stack.length !== 0) {
					const item = stack.shift()!
					let isMatchSearch = true
					//在线会议始终满足search
					if (item.mcc.isMt) {
						//终端
						isMatchSearch = isMatch(item.mcc, keywords)
					} else if (!item.mcc.status.isOnline) {
						//离线会议
						isMatchSearch = isMatch(item.mcc, keywords)
					}
					if (isMatchSearch) {
						result.push({
							mcc: item.mcc,
							nestingLevel: item.nestingLevel,
							mtKey: item.mtKey,
						})
						if (!item.mcc.isMt && item.mcc.status.isOnline) {
							if (
								(item.mtKey === '0.0.0.0_0' || item.mcc.id === '0_1') &&
								openMap[item.mtKey] === undefined
							) {
								//初始化默认展开本级和上级
								openMap[item.mtKey] = true
							}
							newOpenMap[item.mtKey] = openMap[item.mtKey] !== undefined ? openMap[item.mtKey] : false
							if (newOpenMap[item.mtKey]) {
								for (let i = item.children.length - 1; i >= 0; i--) {
									stack.unshift({
										mcc: item.children[i].mcc,
										mtKey: item.children[i].mtKey,
										nestingLevel: item.nestingLevel + 1,
										children: item.children[i].children,
									} as MccModel<IMcc>)
								}
							}
						}
					}
				}
				/**
				 * 由于推送消息都是单条单条处理，所以 tree 的更新存在先后性
				 * 离线会议和被删除的会议需要进行判断，从openMap内移除。否则再次上线可能会默认展开，导致其下级终端并没有出现
				 */
				set((s) => ({ ...s, all: { ...s.all, openMap } }))
			} else {
				let stack = tree.children
				for (let i = 0; i < stack.length; i++) {
					const item = stack[i]
					let isMatchSearch = isMatch(item.mcc, keywords)
					if (isMatchSearch) {
						result.push({
							mcc: item.mcc,
							nestingLevel: 0,
							children: [],
							mtKey: item.mtKey,
						})
					}
				}
			}
			set({ list: result })
		},
		getListFromTable(list, keywords) {
			let result = []
			for (let i = 0; i < list.length; i++) {
				const item = list[i]
				let isMatchSearch = isMatch(item.mcc, keywords)
				if (isMatchSearch) {
					result.push({
						mcc: item.mcc,
						nestingLevel: 0,
						children: [],
						mtKey: item.mtKey,
					})
				}
			}
			set({ list: result })
		},
		clickSelectItem: (data, { ctrlKey, shiftKey }) => {
			//需要过滤会议
			if (!data.isMt) return
			let tab = get().tab
			let prevClickSelectItem = get()[tab]._prevClickSelectItem
			let chosenMap = get()[tab].chosenMap
			const list = get().list
			if (shiftKey) {
				if (prevClickSelectItem) {
					const { start, prevChosen } = prevClickSelectItem
					if (prevChosen.length > 0) {
						//说明已经有过一次shift操作，需要把这次操作结果复原
						for (const item of list) {
							if (prevChosen.includes(item.mtKey)) {
								chosenMap[item.mtKey] = false
							}
						}
					}
					const startItem = list.find((x) => x.mtKey === start)
					let newChosen = []
					if (!startItem || startItem.mtKey === data.mtKey) {
						//比如经过搜索，初始值没了，那就重新记录;或者初始值和当前值一样
						chosenMap[data.mtKey] = true
						prevClickSelectItem.start = data.mtKey
					} else {
						let _flag = false,
							_time = 0
						for (const item of list) {
							if (!item.mcc.isMt) continue
							if (item.mtKey === data.mtKey || item.mtKey === start) {
								chosenMap[item.mtKey] = true
								newChosen.push(item.mtKey)
								_flag = ++_time === 1
							}
							if (_flag) {
								chosenMap[item.mtKey] = true
								newChosen.push(item.mtKey)
							}
						}
					}
					prevClickSelectItem.prevChosen = newChosen
				} else {
					chosenMap[data.mtKey] = true
					prevClickSelectItem = { start: data.mtKey, prevChosen: [] }
				}
			} else {
				if (ctrlKey) {
					chosenMap[data.mtKey] = !chosenMap[data.mtKey]
				} else {
					chosenMap = {
						[data.mtKey]: true,
					}
				}
				prevClickSelectItem = { start: data.mtKey, prevChosen: [] }
			}
			set((s) => ({
				...s,
				[tab]: { ...s[tab], chosenMap: { ...chosenMap }, _prevClickSelectItem: prevClickSelectItem },
			}))
		},
		clearChosen: () => {
			set((s) => ({
				...s,
				all: { ...s.all, _prevClickSelectItem: null, chosenMap: {} },
				often: { _prevClickSelectItem: null, chosenMap: {} },
				interactive: { _prevClickSelectItem: null, chosenMap: {} },
			}))
		},
		itemAddToRight: (data) => {
			const selectedList = get().selectedList
			//去重
			for (let i = 0; i < selectedList.length; i++) {
				if (selectedList[i].mtKey === data.mtKey) return
			}
			selectedList.push({
				mcc: data,
				mtKey: data.mtKey,
				status: {
					checked: false,
				},
			})
			set({ selectedList: [...selectedList] })
			get().clearChosen()
		},
		addAllToRight: () => {
			//todo 应该和添加与会方保持一致，后面再改
			const selectedList = get().selectedList
			const list = get().list
			//去重
			const insertList = differenceBy(list, selectedList, (x) => x.mtKey)
			let result = insertList
				.filter((x) => x.mcc.isMt)
				.map(
					(x) =>
						({
							mcc: x.mcc,
							mtKey: x.mtKey,
							status: {
								checked: false,
							},
						} as SelectedModel)
				)
			set({ selectedList: [...selectedList, ...result] })
		},
		addAllSelectedToRight: () => {
			let tab = get().tab
			const selectedList = get().selectedList
			const chosenMap = get()[tab].chosenMap
			let mtKeys = []
			for (const mtKey in chosenMap) {
				if (chosenMap[mtKey]) {
					mtKeys.push({ mtKey })
				}
			} //去重
			const insertMtKeys = differenceBy(mtKeys, selectedList, (x) => x.mtKey).map((x) => x.mtKey)
			let result: SelectedModel[] = []
			if (tab === 'all') {
				const getMtModel = useTableAllStore.getState().getMtModel
				result = getMtModel(insertMtKeys)
					.map((x) =>
						x
							? {
									mcc: x.mcc,
									mtKey: x.mtKey,
									status: {
										checked: false,
									},
							  }
							: undefined
					)
					.filter(Boolean) as SelectedModel[]
			} else if (tab === 'often') {
				const _oftenList = useTableOftenStore.getState().list
				result = _oftenList
					.filter((x) => insertMtKeys.includes(x.mtKey))
					.map(
						(x) =>
							({
								mcc: x.mcc,
								mtKey: x.mtKey,
								status: {
									checked: false,
								},
							} as SelectedModel)
					)
			} else if (tab === 'interactive') {
				const _interactiveList = useTableInteractiveStore.getState().list
				result = _interactiveList
					.filter((x) => insertMtKeys.includes(x.mtKey))
					.map(
						(x) =>
							({
								mcc: x.mcc,
								mtKey: x.mtKey,
								status: {
									checked: false,
								},
							} as SelectedModel)
					)
			}
			set({ selectedList: [...selectedList, ...result] })
		},
		removeSelectedItem: (mtKey) => {
			const selectedList = get().selectedList
			let s = selectedList.filter((x) => x.mtKey !== mtKey)
			set({ selectedList: s })
		},
		removeSelectedCheckedItem: () => {
			const selectedList = get().selectedList
			let s = selectedList.filter((x) => !x.status.checked)
			set({ selectedList: s })
		},
		removeAllSelectedItem: () => {
			set({ selectedList: [] })
		},
		mtChange2SelectedItem: () => {
			let selectedList = get().selectedList
			let mtKeys = selectedList.map((x) => x.mtKey)
			const getMtModel = useTableAllStore.getState().getMtModel
			let mtModels = getMtModel(mtKeys)
			for (let i = 0; i < selectedList.length; i++) {
				const s = selectedList[i]
				if (mtModels[i]) {
					s.mcc = mtModels[i]!.mcc as Mt
				}
			}
			set({ selectedList: [...selectedList] })
		},
		itemHandle: (mtKey, type) => {
			const { selectedList, _start, _changes } = get()
			const result = listToggle(
				selectedList,
				{
					_start,
					_changes,
					action: type,
				},
				mtKey
			)
			set({ selectedList: result.list, _start: result._start, _changes: result._changes })
		},
	}))
)
